import { Injectable } from '@nestjs/common';
import { PrismaService } from 'src/common/prisma/PrismaService';
import ConfigQueryParam from '../param/ConfigQueryParam';
import ConfigDto from '../dto/ConfigDto';
import { plainToInstance } from 'class-transformer';
import { Util } from 'src/common/Util';
import ServiceException from 'src/common/ServiceException';
import { CacheUtil } from 'src/common/CacheUtil';
import { CacheKey } from 'src/common/CacheKey';
import { Constants } from 'src/common/Constants';

/*
 * @Author: jingfuu@163.com
 * @Date: 2024-11-27 16:52:54
 * @LastEditTime: 2024-12-12 16:45:25
 * @Description: 系统配置服务类
 */
@Injectable()
class SystemConfigService {
  async export(param: ConfigQueryParam) {
    const whereClause: any = this.generatePageQueryCondition(param);
    const sysConfigs = await this.prisma.sysConfig.findMany({
      orderBy: {
        configId: 'desc',
      },
      where: whereClause,
    });
    const configDtos = plainToInstance(ConfigDto, sysConfigs);
    // 设置列头
    const header = [
      { header: '参数主键', key: 'id', width: 10 },
      { header: '参数名称', key: 'configName', width: 20 },
      { header: '参数键名', key: 'configKey', width: 20 },
      { header: '参数键值', key: 'configValue', width: 20 },
      { header: '系统内置', key: 'type', width: 20 },
    ];
    const configs = configDtos.map((config) => {
      return {
        id: config.configId,
        configName: config.configName,
        configKey: config.configKey,
        configValue: config.configValue,
        type: config.configType == 'Y' ? '是' : '否',
      };
    });
    return Util.excelExport(configs, header);
  }
  constructor(private prisma: PrismaService) {}

  async list(param: ConfigQueryParam) {
    const skip = param.pageNum != 0 ? (param.pageNum - 1) * param.pageSize : 0;
    const whereClause: any = this.generatePageQueryCondition(param);
    const [total, configs] = await this.prisma.$transaction([
      this.prisma.sysConfig.count({ where: whereClause }),
      this.prisma.sysConfig.findMany({
        skip,
        take: param.pageSize,
        orderBy: {
          configId: 'desc',
        },
        where: whereClause,
      }),
    ]);
    const rows: ConfigDto[] = plainToInstance(ConfigDto, configs);
    return {
      total,
      rows,
    };
  }
  generatePageQueryCondition(param: ConfigQueryParam): any {
    const whereClause: any = {};

    if (param.configName) {
      whereClause.configName = {
        contains: param.configName,
      };
    }

    if (param.configKey !== undefined) {
      whereClause.configKey = param.configKey;
    }

    if (param.status !== undefined) {
      whereClause.status = param.status;
    }

    if (param.params?.beginTime) {
      const beginTime = Util.convertUTCToLocalTime(
        new Date(`${param.params.beginTime}T10:00:00`),
      );
      if (!isNaN(beginTime.getTime())) {
        // Check if the date is valid
        whereClause.createTime = {
          ...whereClause.createTime,
          gte: beginTime,
        };
      }
    }
    if (param.params?.endTime) {
      const endTime = Util.convertUTCToLocalTime(
        new Date(`${param.params.endTime}T23:59:59`),
      );
      if (!isNaN(endTime.getTime())) {
        // Check if the date is valid
        whereClause.createTime = {
          ...whereClause.createTime,
          lte: endTime,
        };
      }
    }
    return whereClause;
  }

  async delete(id: number) {
    const sysConfig = await this.prisma.sysConfig.findFirst({
      where: { configId: id },
    });
    if (!sysConfig) return;
    await this.prisma.sysConfig.delete({ where: { configId: id } });
    await CacheUtil.delCache(CacheKey.SYSTEM_CONFIG + sysConfig.configKey);
  }

  async getById(id: number) {
    const sysConfig = this.prisma.sysConfig.findUnique({
      where: {
        configId: id,
      },
    });
    return plainToInstance(ConfigDto, sysConfig);
  }

  async add(config: ConfigDto) {
    await this.checkConfigKey(config.configKey, null);
    await this.prisma.sysConfig.create({
      data: {
        configName: config.configName,
        configKey: config.configKey,
        configValue: config.configValue,
        configType: config.configType,
        remark: config.remark,
      },
    });
    await CacheUtil.delCache(CacheKey.SYSTEM_CONFIG + config.configKey);
  }
  async update(config: ConfigDto) {
    await this.checkConfigKey(config.configKey, config.configId);
    await this.prisma.sysConfig.update({
      data: {
        configName: config.configName,
        configKey: config.configKey,
        configValue: config.configValue,
        configType: config.configType,
        remark: config.remark,
      },
      where: {
        configId: config.configId,
      },
    });
    await CacheUtil.delCache(CacheKey.SYSTEM_CONFIG + config.configKey);
  }

  async checkConfigKey(configKey: string, configId: number) {
    const config = await this.prisma.sysConfig.findFirst({
      where: { configKey: configKey },
    });
    if (!configId) {
      if (config) {
        throw new ServiceException('参数键名' + configKey + '已存在');
      }
    } else {
      if (config && config.configId != configId) {
        throw new ServiceException('参数键名' + configKey + '已存在');
      }
    }
  }

  async getConfigValueByConfigKey(configKey: string) {
    let configValue = await CacheUtil.getCacheString(
      CacheKey.SYSTEM_CONFIG + configKey,
    );
    if (!configValue) {
      const sysConfig = await this.prisma.sysConfig.findFirst({
        where: { configKey: configKey },
      });
      if (sysConfig) {
        configValue = sysConfig.configValue;
        await CacheUtil.setCacheObject(
          CacheKey.SYSTEM_CONFIG + configKey,
          configValue,
          3600 * 2,
        );
      }
    }
    return configValue;
  }

  async getUserSessionEffectiveTime(): Promise<number> {
    const timeStr = await this.getConfigValueByConfigKey(
      Constants.USER_SESSION_EXPIRED_TIME,
    );
    if (!timeStr) return 168;
    return parseInt(timeStr);
  }

  async refreshCache() {
    await CacheUtil.deleteKeysWithPrefix(CacheKey.SYSTEM_CONFIG);
  }

  async getUserLoginFailLockFlag(): Promise<boolean> {
    const flagStr = await this.getConfigValueByConfigKey(
      Constants.USER_LOGIN_FAIL_LOCK_FLAG,
    );
    if (flagStr == undefined || flagStr == null) return true;
    return flagStr == 'true';
  }

  async getUserLoginFailLockTime(): Promise<number> {
    const timeStr = await this.getConfigValueByConfigKey(
      Constants.USER_LOGIN_FAIL_TIME,
    );
    if (!timeStr) return 5;
    return parseInt(timeStr);
  }

  async getUserLoginFailLockCount(): Promise<number> {
    const countStr = await this.getConfigValueByConfigKey(
      Constants.USER_LOGIN_FAIL_COUNT,
    );
    if (!countStr) return 3;
    return parseInt(countStr);
  }

  async getUserOpenOperinforFlag() {
    const flagStr = await this.getConfigValueByConfigKey(
      Constants.USER_OPEN_OPERINFOR_FLAG,
    );
    if (flagStr == undefined || flagStr == null) return true;
    return flagStr == 'true';
  }

  async getUserDefaultPassword() {
    let defaultPwd = await this.getConfigValueByConfigKey(
      Constants.USER_DEFAULT_PWD_KEY,
    );
    if (!defaultPwd) {
      defaultPwd = '123456';
    }
    return defaultPwd;
  }

  async getUserCaptchaEnabled() {
    const flagStr = await this.getConfigValueByConfigKey(
      Constants.USER_CAPTCHA_ENABLED,
    );
    if (flagStr == undefined || flagStr == null) return true;
    return flagStr == 'true';
  }

  async getUserCaptchaExpiration() {
    const expirationStr = await this.getConfigValueByConfigKey(
      Constants.USER_CAPTCHA_EXPIRATION,
    );
    if (!expirationStr) return 2;
    return parseInt(expirationStr);
  }

  async getUserOpenLogininforFlag() {
    const flagStr = await this.getConfigValueByConfigKey(
      Constants.USER_OPEN_LOGININFOR_FLAG,
    );
    if (flagStr == undefined || flagStr == null) return true;
    return flagStr == 'true';
  }
}
export default SystemConfigService;
